// type GeoData = {}

import { LayerSpecification } from 'mapbox-gl';

type LayerId = string;

/**
 * 渲染选项文档地址： https://docs.mapbox.com/style-spec/reference/layers/#layer-properties
 * 这页里写了一堆属性， 分别标识是是 layout 还是 paint 属性（或其他对象属性，layout和paint最常用）
 */
export type RenderOptions = {
  /**
   * 名词定义： https://docs.mapbox.com/help/glossary/layout-paint-property/#layout-properties
   * 可选属性： https://docs.mapbox.com/style-spec/reference/layers/#layer-properties
   */
  layout?: LayerSpecification['layout'];
  /**
   * 名词定义： https://docs.mapbox.com/help/glossary/layout-paint-property/#paint-properties
   * 可选属性： https://docs.mapbox.com/style-spec/reference/layers/#layer-properties
   */
  paint?: LayerSpecification['paint'];
  minzoom?: number; // 最小缩放级别
  maxzoom?: number; // 最大缩放级别
};

export interface IMapLayer {
  render(map: mapboxgl.Map): LayerId[];
}

export interface IBaseLayerParams {
  layerId: LayerId;
  sourceId: string;
  map: mapboxgl.Map;
  sort: number;
}

export interface IBaseLayer {
  layerId: LayerId;
  sort: number; // 图层渲染顺序， 越小越后渲染
  allLayerIds?: Set<LayerId>;
  sourceId: string;
  map: mapboxgl.Map;
  // loadSource(): Promise<GeoData>;
  addToMap(): LayerId;
  setVisible(visible: boolean): void; // 设置图层可见性
}

export class BaseLayer implements IBaseLayer {
  sort: number = 0; // 图层渲染顺序， 越小越后渲染
  layerId: LayerId;
  sourceId: string;
  map!: mapboxgl.Map;
  constructor(cfg: IBaseLayerParams, addToMap?: () => LayerId) {
    this.layerId = cfg.layerId;
    this.sourceId = cfg.sourceId;
    this.map = cfg.map;
    cfg.map.on('load', () => {
      this.onload();
    });
    this.sort = cfg.sort;
    if (addToMap) {
      this.addToMap = addToMap;
    }
  }
  /**
   * 添加图层到地图
   * map.addLayer()
   *
   */
  addToMap(): LayerId {
    throw new Error('Method not implemented.');
  }

  hide() {
    this.map.setLayoutProperty(this.layerId, 'visibility', 'none');
  }
  show() {
    this.map.setLayoutProperty(this.layerId, 'visibility', 'visible');
  }

  /**
   * 设置图层可见性
   * @param visible 是否可见
   */
  setVisible(visible: boolean): void {
    if (visible) {
      this.show();
    } else {
      this.hide();
    }
  }

  resize() {
    this.map.resize();
  }

  remove() {
    this.map.remove();
  }

  filter(conditions: mapboxgl.FilterSpecification): mapboxgl.Map | undefined {
    if (!this.map) {
      throw new Error('Map is not set. Please set the map before filtering.');
    }
    console.warn(`Effective based on the BaseLayer`, conditions);
    return this.map.setFilter(this.layerId, conditions);
  }

  onload() {
    console.error(
      `BaseLayer onload is not implemented, please override this method in the subclass.`,
    );
  }

  protected checkLoaded() {
    return this.map.getLayer(this.layerId) !== undefined;
  }
}
